/*
* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
*
* http://www.apache.org/licenses/LICENSE-2.0 
*
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/
const { replaceAll, getPrefix, getConstNum } = require("../tools/tool");
const { paramGenerate } = require("./param_generate");
const { returnGenerate } = require("./return_generate");

/**
 * 结果异步返回Async|Promise
 */
let funcAsyncTemplete = `
struct [funcName]_value_struct {[valueIn]
    uint32_t outErrCode = 0;[valueOut]
};

[static_define]void [funcName]_execute(XNapiTool *pxt, DataPtr data)
{
    void *data_ptr = data;
    [funcName]_value_struct *vio = static_cast<[funcName]_value_struct *>(data_ptr);
    [checkout_async_instance]
    [callFunc]
}

[static_define]void [funcName]_complete(XNapiTool *pxt, DataPtr data)
{
    void *data_ptr = data;
    [funcName]_value_struct *vio = static_cast<[funcName]_value_struct *>(data_ptr);
    napi_value result = nullptr;
    [valuePackage]
    napi_value errCodeResult = nullptr;
    napi_value napiErrCode = nullptr;
    napiErrCode = NUMBER_C_2_JS(pxt, vio->outErrCode);
    pxt->SetValueProperty(errCodeResult, "code", napiErrCode);
    {
        napi_value args[XNapiTool::TWO] = {errCodeResult, result};
        pxt->FinishAsync(XNapiTool::TWO, args);
    }
    [optionalParamDestory]
    delete vio;
}

[static_define]napi_value [funcName]_middle(napi_env env, napi_callback_info info)
{
    XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release();
    if (pxt->IsFailed()) {
        napi_value err = pxt->GetError();
        delete pxt;
        return err;
    }
    [unwarp_instance]
    struct [funcName]_value_struct *vio = new [funcName]_value_struct();
    [valueCheckout][optionalCallbackInit][start_async]
    if (pxt->IsFailed()) {
        result = pxt->GetError();
    }
    return result;
}`

let cppTemplate = `
bool %s%s(%s)
{
    return true;
}
`

function removeEndlineEnter(value) {
    for (var i = value.length; i > 0; i--) {
        let len = value.length
        if (value.substring(len - 1, len) == "\n" || value.substring(len - 1, len) == ' ') {
            value = value.substring(0, len - 1)
        } else {
            value = '    ' + value + "\n"
            break
        }
    }
    return value
}

function getOptionalCallbackInit(param) {
    if (!param.callback.optional) {
        return ""
    }
    let cType = param.valueOut.substr(0, param.valueOut.indexOf("*"))
    return "vio->out = new %s;".format(cType)
}

function replaceBasicInfo(middleFunc, className) {
    if (className == null) {
        middleFunc = middleFunc.replaceAll("[static_define]", "")
        middleFunc = middleFunc.replaceAll("[unwarp_instance]", "")
        middleFunc = middleFunc.replaceAll("[checkout_async_instance]", "")
    }
    else {
        middleFunc = middleFunc.replaceAll("[static_define]", "static ")
        middleFunc = middleFunc.replaceAll("[unwarp_instance]",
            `pxt->SetAsyncInstance(pxt->UnWarpInstance());`)
        middleFunc = middleFunc.replaceAll("[checkout_async_instance]",
            "%s *pInstance = (%s *)pxt->GetAsyncInstance();".format(className, className))
    }
    return middleFunc
}
function generateFunctionAsync(func, data, className) {
    let middleFunc = replaceAll(funcAsyncTemplete, "[funcName]", func.name)
    middleFunc = replaceBasicInfo(middleFunc, className)

    // 定义输入,定义输出,解析,填充到函数内,输出参数打包,impl参数定义,可选参数内存释放
    let param = { valueIn: "", valueOut: "", valueCheckout: "", valueFill: "",
        valuePackage: "", valueDefine: "", optionalParamDestory: "" }

    for (let i in func.value) {
        paramGenerate(i, func.value[i], param, data)
    }
    returnGenerate(param.callback, param, data)

    middleFunc = replaceAll(middleFunc, "[valueIn]", param.valueIn) // # 输入参数定义
    if (param.valueOut == "") {
        middleFunc = replaceAll(middleFunc, "[valueOut]", param.valueOut) // # 输出参数定义
    } else {
        middleFunc = replaceAll(middleFunc, "[valueOut]", "\n    " + param.valueOut) // # 输出参数定义
    } 
    if (param.valueCheckout == "") {
        middleFunc = replaceAll(middleFunc, "[valueCheckout]", param.valueCheckout) // # 输入参数解析
    } else {
        param.valueCheckout = removeEndlineEnter(param.valueCheckout)
        middleFunc = replaceAll(middleFunc, "[valueCheckout]", param.valueCheckout) // # 输入参数解析
    }
    let optionalCallback = getOptionalCallbackInit(param)
    if (optionalCallback == "") {
        middleFunc = replaceAll(middleFunc, "[optionalCallbackInit]", optionalCallback) // 可选callback参数初始化
    } else {
        middleFunc = replaceAll(middleFunc, "[optionalCallbackInit]", optionalCallback + "\n    ") // 可选callback参数初始化
    }
    middleFunc = replaceAll(middleFunc, "[start_async]", `
    napi_value result = pxt->StartAsync(%s_execute, reinterpret_cast<DataPtr>(vio), %s_complete,
    pxt->GetArgc() == %s? pxt->GetArgv(%d) : nullptr);`
        .format(func.name, func.name, getConstNum(parseInt(param.callback.offset) + 1),
        getConstNum(param.callback.offset))) // 注册异步调用
    let callFunc = "%s%s(%s);".format(className == null ? "" : "pInstance->", func.name, param.valueFill)
    middleFunc = replaceAll(middleFunc, "[callFunc]", callFunc) // 执行
    middleFunc = replaceAll(middleFunc, "[valuePackage]", param.valuePackage) // 输出参数打包
    middleFunc = replaceAll(middleFunc, "[optionalParamDestory]", param.optionalParamDestory) // 可选参数内存释放

    let prefixArr = getPrefix(data, func)
    let implH = ""
    let implCpp = ""
    if (!func.isParentMember) {
        // 只有类/接口自己的成员方法需要在.h.cpp中生成，父类/父接口不需要
        implH = "\n%s%s%sbool %s(%s)%s;".format(
            prefixArr[0], prefixArr[1], prefixArr[2], func.name, param.valueDefine, prefixArr[3])
        implCpp = cppTemplate.format(className == null ? "" : className + "::", func.name, param.valueDefine)
    }
    return [middleFunc, implH, implCpp]
}

module.exports = {
    generateFunctionAsync
}